#ifndef TRANSFORMERCONTENTQUERYTARGET_HPP_3
#define TRANSFORMERCONTENTQUERYTARGET_HPP_3

#include "logger.hpp"
#include "transContentDefine.h"
#include "transContentErrorCode.h"
#include "transContentDispatcher.hpp"

class TransContentFuncCallQueryTarget{
	private:
	int timeout;
	int localPort;
	int queryCondType;
	int queryValueLen;
	int canBeRemoved;
	int operationResult;
	NodeAddr target;
	char queryCondValue[MAX_DEVICEID_LEN];
	queryTargetCallback qtcb;
	deviceInfo resultInfo;
	pthread_mutex_t waitMutex;
	pthread_cond_t waitCond;

public:
	TransContentFuncCallQueryTarget(): timeout(INT_MAX), localPort(0), queryCondType(QUERY_DEVICE_COND_IMEI), queryValueLen(0), canBeRemoved(0), operationResult(0), qtcb(NULL), waitMutex(PTHREAD_MUTEX_INITIALIZER), waitCond(PTHREAD_MUTEX_INITIALIZER){
	}
	~TransContentFuncCallQueryTarget();
	
	void setTimeout(int timeout){
		this->timeout = timeout;
	}
	int getTimeout(){
		return this->timeout;
	}

	int getOperationResult(){
		return operationResult;
	}

	void setTarget(const NodeAddr* target){
		this->target = *target;
	}

	NodeAddr getTarget(){
		return this->target;
	}

	int getCanBeRemoved(){
		return canBeRemoved;
	}

	void setLocalPort(int port){
		this->localPort = port;
	}
	int getLocalPort(){
		return this->localPort;
	}
	
	void setQueryValue(int type, void* value, int len){
		memset(queryCondValue, 0x00, MAX_DEVICEID_LEN);
		memcpy(queryCondValue, value, len);
		queryValueLen = len;
		queryCondType = type;
	}
	int getQueryCondType(int* type, void* value, int len){
		*type = queryCondType;
	   memcpy(value, queryCondValue, queryValueLen);
		return queryValueLen;	   
	}
	
	void setFinishedCallback(queryTargetCallback qtcb){
		this->qtcb = qtcb;
	}
	queryTargetCallback getFinishedCallback(){
		return this->qtcb;
	}
	
	int query(deviceInfo* dInfo);
	int response(char* content, int index);
	
	
private:
	///////////////////////////////////////////////////////////////////////////////////////////
	/// query device info packet out:
	///  name | length | mainCode| subCode | localPort | targetDevice | queryCondType | queryCondValueLen | queryCondValue | 
	/// length|    2   |    1    |    1    |     4     |    8         |       1       |       1           |     valuelen   |
	/// offset|    0   |    2    |    3    |     4     |    8         |        16     |       17          |     18         |
	///
	/// query devcie response packet, the start the same as query info packet out
	///  name | result |showMe| nickLen |  nick  | dIdLen |   dId   |  imei   | ttl    |
	/// lenth |   1    |   1  |   1     |   xx   |   1    |    xx   |    16   |  1     |
	/// offset|  17+v  | 18+v |   19+v  |  20+v  | 20+v+n | 21+v+n  | 21+v+n+d|37+v+n+d| 

	static void setPacketLength(char* buffer, int length){
		*((short*)(buffer)) = (short)length;
	}

	static int getPacketLength(const char* buffer){
		return *((short*)(buffer));
	}

	static void setPacketMainMessage(char* buffer, int code){
		buffer[2] = (char)code;
	}

	static int getPacketMainMessage(const char* buffer, int towards){
		return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[0] : buffer[2];
	}

	static void setPacketSubMessageCode(char* buffer, int code){
		buffer[3] = (char)code;
	}

	static int getPacketSubMessageCode(const char* buffer, int towards){
		return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[1] : buffer[3];
	}

	static void setPacketLocalPort(char* buffer, int port){
		*((int*)(buffer+4)) = port;
	}

	static int getPacketLocalPort(const char* buffer, int towards){
		return towards==DUMP_PROTOCOL_PACKET_IN ? *((int*)(buffer+2)) : *((int*)(buffer+4));
	}

	static void setPacketTarget(char* buffer, const NodeAddr* target){
		*((long long*)(buffer+8)) = target->serial_id;
	}

	static NodeAddr getPacketTarget(const char* buffer, int towards){
		NodeAddr tempAddr;
		tempAddr.serial_id = towards==DUMP_PROTOCOL_PACKET_IN ? *((long long*)(buffer+6)) : *((long long*)(buffer+8));
		return tempAddr;
	}

	static void setPacketQueryValueType(char* buffer, int type){
		buffer[16] = (char)type;
	}

	static int getPacketQueryValueType(const char* buffer, int towards){
		return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[14]:buffer[16];
	}

	static void setPacketQueryValueLen(char* buffer, int len){
		buffer[17] = (char)len;
	}

	static int getPacketQueryValueLen(const char* buffer, int towards){
		return towards==DUMP_PROTOCOL_PACKET_IN ? buffer[15]:buffer[17];
	}

	static void setPacketQueryValue(char* buffer, const char* value, int valuelen){
		memcpy(buffer+18, value, valuelen);
	}

	static int getPacketQueryValue(const char* buffer, char* value, int valueLen, int towards){
		int len = getPacketQueryValueLen(buffer, towards);
		towards==DUMP_PROTOCOL_PACKET_IN ? memcpy(value, buffer+16, len): memcpy(value, buffer+18, len);
		return len;
	}

	//only for in packet
	static int getPacketQueryResult(const char* buffer){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		return buffer[QueryValueLen+17];
	}

	static int getPacketDeviceInfoNickLen(const char* buffer){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		return buffer[QueryValueLen+19];
	}

	static int getPacketDeviceInfoNick(const char* buffer, char* nick, int len){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
		memcpy(buffer+20+QueryValueLen, nick, nickValueLen);
		return nickValueLen;
	}

	// the same as result
	static int getPacketDeviceInfoShowMe(const char* buffer){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		return buffer[QueryValueLen+18];
	}

	static int getPacketDeviceInfoDeviceIdLen(const char* buffer){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
		return buffer[20 + QueryValueLen + nickValueLen];
	}

	static int getPacketDeviceInfoDeviceId(const char* buffer, char* deviceId, int length){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
		int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
		memcpy(deviceId, buffer+21+QueryValueLen+nickValueLen, deviceIdLen);
		return deviceIdLen;
	}

	static int getPacketDeviceInfoDeviceIMEI(const char* buffer, char* imei, int length){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
		int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
		memcpy(imei, buffer+21+QueryValueLen+nickValueLen+deviceIdLen, 16);
		return 16;
	}

	static int getPacketDeviceInfoTTL(const char* buffer){
		int QueryValueLen = getPacketQueryValueLen(buffer, DUMP_PROTOCOL_PACKET_IN);
		int nickValueLen =  getPacketDeviceInfoNickLen(buffer);
		int deviceIdLen = getPacketDeviceInfoDeviceIdLen(buffer);
		return buffer[37+QueryValueLen+nickValueLen+deviceIdLen];
	}

	static void dumpPacket(const char* buffer, int towards, const char* fileName){
		FILE* dumpFile = fopen(fileName, "w+");
		char timer[256]={0};
		if(dumpFile == NULL){
			return;
		}   
		TransContentSetting::getTimeStr(timer, 256);
		fprintf(dumpFile, "\t\t\t\tdump function call query target protocol\n");
		fprintf(dumpFile, "\ttime stamp: %s\n", timer);
	
		if(towards==DUMP_PROTOCOL_PACKET_OUT){
			fprintf(dumpFile, "\tpacket length: %d\n", getPacketLength(buffer));
		}
		fprintf(dumpFile, "\tpacket main code: %d\n", getPacketMainMessage(buffer, towards));
		fprintf(dumpFile, "\tpacket sub code: %d\n", getPacketSubMessageCode(buffer, towards));
		fprintf(dumpFile, "\tpacket localPort: %d\n", getPacketLocalPort(buffer, towards));
		fprintf(dumpFile, "\tpacket target addr: %lld\n", getPacketTarget(buffer, towards).serialId);
		fprintf(dumpFile, "\tpacket query type: %d\n", getPacketQueryValueType(buffer, towards));
		fprintf(dumpFile, "\tpacket query value len: %d\n", getPacketQueryValueLen(buffer, towards));
		memset(timer, 0x00, 256);
		fprintf(dumpFile, "\tpacket query value: %s\n", getPacketQueryValue(buffer, timer, 256, towards));
		if(towards==DUMP_PROTOCOL_PACKET_IN){
			fprintf(dumpFile, "\tpacket query result: %d\n", getPacketQueryResult(buffer));
			fprintf(dumpFile, "\tpacket query response: showMe: %d\n", getPacketDeviceInfoShowMe(buffer));
			fprintf(dumpFile, "\tpacket query response: nickLen: %d\n", getPacketDeviceInfoNickLen(buffer));
			memset(timer, 0x00, 256);
			fprintf(dumpFile, "\tpacket query response: nick: %s\n", getPacketDeviceInfoNick(buffer, timer, 256));
			fprintf(dumpFile, "\tpacket query response: deviceId length: %d\n", getPacketDeviceInfoDeviceIdLen(buffer));
			memset(timer, 0x00, 256);
			fprintf(dumpFile, "\tpacket query response: deviceId value: %s\n", getPacketDeviceInfoDeviceId(buffer, timer, 256));
			memset(timer, 0x00, 256);
			fprintf(dumpFile, "\tpacket query response: IMEI: %s\n", getPacketDeviceInfoDeviceIMEI(buffer, timer, 256));
			fprintf(dumpFile, "\tpacket query response: TTL: %d\n", getPacketDeviceInfoTTL(buffer));
		}
	}
};
#endif //TRANSFORMERCONTENTQUERYTARGET_HPP_3
